/*
 * @Author: january.cjy
 * @Date: 2021-09-27 19:52:30
 * @Last Modified by: january.cjy
 * @Last Modified time: 2021-11-02 19:21:33
 */
#include <CmgRecursiveASTVisitor.h>

#include "clang/Basic/FileManager.h"
#include <string>

namespace cmg {
// extern FileFeature fileFeature;
CmgRecursiveASTVisitor::CmgRecursiveASTVisitor(ASTContext &ctx,
                                               SourceManager &sm,FileFeature &feature)
    : ctx(ctx), sm(sm),fileFeature(feature){}

/*bool CmgRecursiveASTVisitor::VisitDecl(Decl *d) {
  if (NamedDecl *nd = llvextern FileFeature fileFeature;m::dyn_cast<NamedDecl>(d)) {
    llvm::outs() << nd->getName() << "\t@ ";
    llvm::outs() << sm.getFilename(sm.getSpellingLoc(d->getBeginLoc())) << "\n";
    llvm::outs() <<sm.getFileID(sm.getSpellingLoc(d->getBeginLoc())).getHashValue()<<"\n";
  }
  // clang::FileID fid = sm.getFileID(sm.getSpellingLoc(d->getBeginLoc()));
  // clang::FileManager &fm = sm.getFileManager();
  return true;
}*/

//0:全局 1：本地 2：局部
int CmgRecursiveASTVisitor::isGlobal(DynTypedNode node){
  const DynTypedNodeList& parents=ctx.getParents(node);
  if(parents[0].getNodeKind ().asStringRef ()=="TranslationUnitDecl")
    return 0;
  if(parents[0].getNodeKind ().asStringRef ()=="NamespaceDecl"){
    const NamespaceDecl *namespaceDecl=parents[0].get<NamespaceDecl>();
    if(namespaceDecl->isAnonymousNamespace ()){
      return 1;
    }
    return isGlobal(parents[0]);
  }
  return 2;
}

void CmgRecursiveASTVisitor::countSymbol(int isDeclOrDef,unsigned int& decl,unsigned int& def){
  if(isDeclOrDef!=0){
         def++;
  }else{
         decl++;
  }
}
// bool CmgRecursiveASTVisitor::VisitTranslationUnitDecl(TranslationUnitDecl *tranc){
//   //copy();
//   return true;
// }
//TagDecl 包含{struct/union/class/enum}  
//isGlobal确定全局 本地 局部 
//使用isThisDeclarationADefinition ()判断类型声明和定义
 bool CmgRecursiveASTVisitor::VisitTagDecl(TagDecl *tagc){
   unsigned int fid=sm.getFileID(sm.getSpellingLoc(tagc->getBeginLoc())).getHashValue();
   if(!fileFeature.isExist(fid)){
      string fileName=sm.getFilename(sm.getSpellingLoc(tagc->getBeginLoc())).str();
      string fileType = fileName.substr(fileName.find_last_of('.') + 1);
      Feature tempFeature(fid,fileName,fileType);
      fileFeature.addFeature(fid,tempFeature);
      //llvm::outs() << "enter"<< "\n";
   }
   Feature& feature=fileFeature.getFeature(fid);
   int DeclOrDef=tagc->isThisDeclarationADefinition ();

   DynTypedNode dynTypedNode=dynTypedNode.create<TagDecl>(*tagc);
   int judge=isGlobal(dynTypedNode); 
   //llvm::outs() << judge << "\n";
   //局部类不统计 ？局部静态类
   if(judge==2){
     
   }
   //匿名空间中的类
   else if(judge==1){
      countSymbol(DeclOrDef,feature.localSymbolDecl,feature.localSymbolDef);
   }
   //统计全局类
   else if(judge==0){
     countSymbol(DeclOrDef,feature.typeDecl,feature.typeDef);
   }
   return true;
 }
  //FunctionDecl包含{function declaration or definition} 
  //isGlobal确定全局 本地 局部  
  //isStatic()确定静态函数  isInlineSpecified ()确定内联函数
  //isThisDeclarationADefinition ()判断声明或定义
  bool CmgRecursiveASTVisitor::VisitFunctionDecl(FunctionDecl *func){
    unsigned int fid=sm.getFileID(sm.getSpellingLoc(func->getBeginLoc())).getHashValue();  
    if(!fileFeature.isExist(fid)){
       string fileName=sm.getFilename(sm.getSpellingLoc(func->getBeginLoc())).str();
       string fileType = fileName.substr(fileName.find_last_of('.') + 1);
       Feature tempFeature(fid,fileName,fileType);
       fileFeature.addFeature(fid,tempFeature);
    }
    Feature& feature=fileFeature.getFeature(fid);
    int DeclOrDef=func->isThisDeclarationADefinition ();

    DynTypedNode dynTypedNode=dynTypedNode.create<FunctionDecl>(*func);
    int judge=isGlobal(dynTypedNode);

    //统计局部静态函数
    if(judge==2){
      if(func->isStatic()){
        countSymbol(DeclOrDef,feature.localSymbolDecl,feature.localSymbolDef);
      }
    }
    //统计匿名空间函数
    else if(judge==1){
           if(func->	isThisDeclarationADefinition ()!=0){
              feature.localSymbolDef++;
           }else{
              feature.localSymbolDecl++;
           }
    }
    //统计全局函数 区分全局静态与否 区分全局内联与否
    else if(judge==0){
      countSymbol(DeclOrDef,feature.funcDecl,feature.funcDef);
      if(func->isStatic()){
        countSymbol(DeclOrDef,feature.staticFuncDecl,feature.staticFuncDef);
      }
      if(func->isInlineSpecified()){
        countSymbol(DeclOrDef,feature.inlineFuncDecl,feature.inlineFuncDef);
      }
    }
    return true;
  }

  //VarDecl 包含{variable declaration or definition} 
  //isGlobal确定全局 本地 局部  
  //varc->isStaticLocal ()判断局部静态变量
  //varc->getStorageClass()判断是否为全局静态变量 ？
  //isThisDeclarationADefinition()判断全局变量为声明或定义
 bool CmgRecursiveASTVisitor::VisitVarDecl(VarDecl *varc){
    unsigned int fid=sm.getFileID(sm.getSpellingLoc(varc->getBeginLoc())).getHashValue();  
    if(!fileFeature.isExist(fid)){
       string fileName=sm.getFilename(sm.getSpellingLoc(varc->getBeginLoc())).str();
       string fileType = fileName.substr(fileName.find_last_of('.') + 1);
       Feature tempFeature(fid,fileName,fileType);
       fileFeature.addFeature(fid,tempFeature);
    }
    Feature& feature=fileFeature.getFeature(fid);
    int DeclOrDef=varc->isThisDeclarationADefinition ();

    DynTypedNode dynTypedNode=dynTypedNode.create<VarDecl>(*varc);
    int judge=isGlobal(dynTypedNode);

    //处理匿名空间中的变量
   if(judge==1){
      countSymbol(DeclOrDef,feature.localSymbolDecl,feature.localSymbolDef);
   }
   //将局部静态变量加入本地符号
   //包含函数内局部静态变量和类内局部静态变量
  else if(judge==2){
      if(varc->isStaticLocal ()||varc->isStaticDataMember ()){
        countSymbol(DeclOrDef,feature.localSymbolDecl,feature.localSymbolDef);
      }
   }
   //处理全局变量，其中区分静态与否
   else if(judge==0){
     countSymbol(DeclOrDef,feature.globalVarDecl,feature.globalVarDef);
     //?
     if(varc->getStorageClass()==SC_Static){
       countSymbol(DeclOrDef,feature.globalStaticVarDef,feature.globalStaticVarDef);
     }
   }
  return true;
 }

 //TypedefDecl 包含{typedef-name}
 bool CmgRecursiveASTVisitor::VisitTypedefDecl(TypedefDecl *typec){
   unsigned int fid=sm.getFileID(sm.getSpellingLoc(typec->getBeginLoc())).getHashValue();
   if(!fileFeature.isExist(fid)){
      string fileName=sm.getFilename(sm.getSpellingLoc(typec->getBeginLoc())).str();
      string fileType = fileName.substr(fileName.find_last_of('.') + 1);
      Feature tempFeature(fid,fileName,fileType);
      fileFeature.addFeature(fid,tempFeature);
   }
   Feature& feature=fileFeature.getFeature(fid);
   //统计别名
   feature.typeNameDecl++;
   return true;
 }

 
 // ClassTemplateDecl {class template} 
 // isGlobal确定全局 本地 局部 
 // isThisDeclarationADefinition ()判断模板类为定义声明
 bool CmgRecursiveASTVisitor::VisitClassTemplateDecl(ClassTemplateDecl *templatec){
   unsigned int fid=sm.getFileID(sm.getSpellingLoc(templatec->getBeginLoc())).getHashValue();
   if(!fileFeature.isExist(fid)){
      string fileName=sm.getFilename(sm.getSpellingLoc(templatec->getBeginLoc())).str();
      string fileType = fileName.substr(fileName.find_last_of('.') + 1);
      Feature tempFeature(fid,fileName,fileType);
      fileFeature.addFeature(fid,tempFeature);
   }
   Feature& feature=fileFeature.getFeature(fid);
   int DeclOrDef=templatec->isThisDeclarationADefinition ();

   DynTypedNode dynTypedNode=dynTypedNode.create<ClassTemplateDecl>(*templatec);
   int judge=isGlobal(dynTypedNode);

   //处理匿名空间模板类
   if(judge==1){
     countSymbol(DeclOrDef,feature.localSymbolDecl,feature.localSymbolDef);
   }
   //处理局部模板类
   else if(judge==2){

   }
   //处理全局模板类
   else if(judge==0){
     countSymbol(DeclOrDef,feature.templateTypeDecl,feature.templateTypeDef);
   }
   
   return true;
 }
 //FunctionTemplateDecl{template function}
 //isGlobal确定全局 本地 局部 
 //isThisDeclarationADefinition ()判断模板函数定义声明
  bool CmgRecursiveASTVisitor::VisitFunctionTemplateDecl(FunctionTemplateDecl *templatefunc){
   unsigned int fid=sm.getFileID(sm.getSpellingLoc(templatefunc->getBeginLoc())).getHashValue();
   if(!fileFeature.isExist(fid)){
      string fileName=sm.getFilename(sm.getSpellingLoc(templatefunc->getBeginLoc())).str();
      string fileType = fileName.substr(fileName.find_last_of('.') + 1);
      Feature tempFeature(fid,fileName,fileType);
      fileFeature.addFeature(fid,tempFeature);
   }
   Feature& feature=fileFeature.getFeature(fid);
   int DeclOrDef=templatefunc->isThisDeclarationADefinition ();

   DynTypedNode dynTypedNode=dynTypedNode.create<FunctionTemplateDecl>(*templatefunc);
   int judge=isGlobal(dynTypedNode);

   //处理匿名空间模板函数
   if(judge==1){
     countSymbol(DeclOrDef,feature.localSymbolDecl,feature.localSymbolDef);
   }
   //处理局部模板函数
   else if(judge==2){
  
   }
   //处理全局模板函数
   else if(judge==0){
     countSymbol(DeclOrDef,feature.templateFuncDecl,feature.templateFuncDef);
   }
   return true;
  }
} // namespace cmg